#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>

#define STDLEN 1024
#define ARGVLEN 32
#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"

char pwd[STDLEN];
char cline[STDLEN];
char* argv[ARGVLEN];
int lastcode = 0;

const char* getusername()
{
    return getenv("USER");
}

const char* gethostname()
{
    return getenv("HOSTNAME");
}

void getpwd()
{
    getcwd(pwd, sizeof(pwd));
}

void interact(char* _cline, int size)
{
    getpwd();
    printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(), gethostname(), pwd);
    char* r = fgets(_cline, size, stdin);
    assert(r);
    (void)r;
    _cline[strlen(_cline)-1] = '\0';
}

int splitstring(char* _cline, char* _argv[])
{
    int i = 0;
    _argv[i++] = strtok(_cline, DELIM);
    while(_argv[i++] = strtok(NULL, DELIM));
    return i-1;
}

int buildcommand(char* _argv[], int argc)
{
    if (argc == 2 && strcmp(_argv[0], "cd") == 0)
    {
        chdir(_argv[1]);
        getpwd();
        sprintf(getenv("PWD"), "%s", pwd);
        return 1;
    }

    if (argc == 2 && strcmp(_argv[0], "echo") == 0)
    {
        if (strcmp(_argv[1], "$?") == 0)
        {
            printf("%d\n", lastcode); 
            lastcode = 0;
        }
        else if ((*_argv[1]) == '$')
        {
            char* val = getenv(_argv[1]+1);
            if (val) printf("%s\n", val);
        }
        else
        {
            printf("%s\n", _argv[1]);
        }
        return 1;
    }

    char myenv[STDLEN];
    if (argc == 2 && strcmp(_argv[0], "export") == 0)
    {
        strcpy(myenv, _argv[1]);
        putenv(myenv);
        return 1;
    }


    if (strcmp(_argv[0], "ls") == 0)
    {
        _argv[argc++] = "--color";
        _argv[argc] = NULL;
    }
    return 0;
}

void normalcommand(char* _argv[])
{
    pid_t id = fork();

    if (id < 0)
    {
        perror("fork_error::");
        return;
    }
    else if (id == 0)
    {
        execvp(_argv[0], _argv);
        exit(1);
    }
    else
    {
        int status = 0;
        int rid = waitpid(id, &status, 0);
        if (rid == id)
        {
            lastcode = WEXITSTATUS(status);

        }
    }
}

int main()
{
    while (1)
    {
        // 1.shell互动
        interact(cline, sizeof(cline));

        // 2.字符串分割
        int ret1 = splitstring(cline, argv);
        if (ret1 == 0) continue;

        // 3.内建指令
        int ret2 = buildcommand(argv, ret1);
        if (ret2 == 1) continue;

        // 4.普通命令
        normalcommand(argv);
    }
    return 0;
}



